package com.coscon.rebatesharing.common.dao;

import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;



/**
 * @Description DAO基类,实现了实体的基本增删改查列表分页方法,
 * 	<br/>所有DAO的实现必须继承该类
 * @author  chenlei
 * @version  1.0
 */
@SuppressWarnings("unchecked")
public abstract class BaseDaoImpl implements BaseDaoInter {

	@Autowired 
	protected SessionFactory sessionFactory;
	
	/**
	 * 查找实体
	 * @param <T> 动态传入实体类
	 * @param entityClass 实体类
	 * @param pk 主键
	 * @return 根据指定主键返回的实体
	 * @throws IllegalArgumentException 
	 */
	public <T> T get(Class <T> entityClass, Object primaryKey) {
		if(!(primaryKey instanceof Serializable)){
			throw new IllegalArgumentException("参数primaryKey需要实现Serializable接口");
		}
		return (T) sessionFactory.getCurrentSession().get(entityClass, (Serializable) primaryKey);
	}
	
	/**
	 * 保存实体
	 * @param entity 需要保存的实体
	 */
	public void save(Object entity) {
		sessionFactory.getCurrentSession().save(entity);
	}
	
	/**
	 * 更新实体
	 * @param entity 需要保存的实体
	 */
	public void update(Object entity) {
		sessionFactory.getCurrentSession().saveOrUpdate(entity);
	}
	
	/**
	 * 删除实体
	 * @param entityClass 需要删除实体类
	 * @param pk 需要删除的实体主键
	 * @throws IllegalArgumentException 
	 */
	public void delete(Class<?> entityClass, Object primaryKey) {
		sessionFactory.getCurrentSession().delete(this.get(entityClass, primaryKey));
	}
	
	@Override
	public <T> T find(Class<T> entityClass, String whereJpql) {
		//获取实体类的实体名。默认情况下，实体名和类名相同
		String entityName = entityClass.getSimpleName();
		//创建查询
		Query query = sessionFactory.getCurrentSession().createQuery("select o from "+ entityName
				+ " as o " + whereJpql);
		return (T) query.uniqueResult();
	}
	
	public <T> List<T> getResultList(Class<T> entityClass 
		, String whereJpql 
		, LinkedHashMap<String, String> orderBy
		, Object... args) {
		//获取实体类的实体名。默认情况下，实体名和类名相同
		String entityName = entityClass.getSimpleName();
		//创建查询
		Query query = sessionFactory.getCurrentSession().createQuery("select o from "+ entityName
			+ " as o " + whereJpql + buildOrderby(orderBy));
		//为查询字符串中参数设置值
		for (int i = 0 ; i < args.length ; i++) {
			query.setParameter(i + 1 , args[i]);
		}
		//返回结果集
		return (List<T>)query.list();
	}
	
	public <T> List<T> getResultList(Class<T> entityClass 
		, String whereJpql 
		, int firstResult 
		, int maxResult 
		, LinkedHashMap<String, String> orderBy
		, Object... args) {
		//获取实体类的实体名。默认情况下，实体名和类名相同
		String entityName = entityClass.getSimpleName();
		//创建查询
		Query query = sessionFactory.getCurrentSession().createQuery("select o from "+ entityName
			+ " as o " + whereJpql + buildOrderby(orderBy));
		//为查询字符串中参数设置值
		for (int i = 0 ; i < args.length ; i++) {
			query.setParameter(i + 1 , args[i]);
		}
		//对查询结果集进行分页
		query.setMaxResults(maxResult).setFirstResult(firstResult);
		//返回结果集
		return (List<T>)query.list();
	}
	
	public <T> int getResultCount(Class<T> entityClass
			, String whereJpql
			, Object... args) {
		//获取实体类的实体名。默认情况下，实体名和类名相同
		String entityName = entityClass.getSimpleName();
		//创建查询
		Query query = sessionFactory.getCurrentSession().createQuery("select count(*) from "+ entityName
			+ " as o " + whereJpql);
		//为查询字符串中参数设置值
		for (int i = 0 ; i < args.length ; i++) {
			query.setParameter(i + 1 , args[i]);
		}
		return Integer.parseInt(query.uniqueResult().toString());
	}
	
	/**
	 * 构建排序子句
	 * @param orderby LinkedHashMap对象，每个key-value对指定一个排序条件
	 */ 
	private static String buildOrderby(LinkedHashMap<String , String> orderby) {
		StringBuffer out = new StringBuffer("");
		if(orderby != null && orderby.size() > 0) {
			//添加order by 子句
			out.append(" order by ");
			//遍历LinkedHashMap中的每个key-value对，
			//每个key-value对生成一个排序条件
			for(String key : orderby.keySet())
			{
				out.append("o." + key + " " + orderby.get(key));
				out.append(",");
			}
			out.deleteCharAt(out.length()-1);
		}
		return out.toString();
	}
}